package cn.tedu.charging.order.mqtt;

import cn.tedu.charging.commen.JsonResult;
import cn.tedu.charging.commen.pojo.param.ChargingProcessParam;
import cn.tedu.charging.commen.pojo.param.GunStatusUpdateParam;
import cn.tedu.charging.commen.pojo.vo.ChargingProcessVO;
import cn.tedu.charging.commen.utils.JsonUtils;
import cn.tedu.charging.order.common.ChargingConstants;
import cn.tedu.charging.order.common.GunStatusConstants;
import cn.tedu.charging.order.common.MqttConstants;
import cn.tedu.charging.order.common.OrderStatusConstants;
import cn.tedu.charging.order.pojo.dto.ChargingProcessDto;
import cn.tedu.charging.order.pojo.dto.ChargingResultDto;
import cn.tedu.charging.order.pojo.po.ChargingOrderFailPO;
import cn.tedu.charging.order.pojo.po.ChargingOrderSuccessPO;
import cn.tedu.charging.order.pojo.po.ChargingProcessPO;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.beans.BeanUtils;

@Slf4j
public class MqttConsumer implements MqttCallbackExtended {
    private MqttClient mqttClient;
    private MqttContext mqttContext;
    /**
     * 没有在容器中的MqttConsumer想使用在容器中的MqttClient
     * 可以在创建MqttConsumer 的时候，通过构造函数注入
     * 也可以通过setter方法注入
     * @param mqttClient
     */
    public MqttConsumer(MqttClient mqttClient,MqttContext mqttContext){
        this.mqttClient = mqttClient;
        this.mqttContext = mqttContext;
    }

    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        log.debug("连接完成，是否重连:{},服务器地址:{}",reconnect,serverURI);
        String topicChargingResult = MqttConstants.TOPIC_CHARGING_RESULT;
        String topicChargingProcess = MqttConstants.TOPIC_CHARGING_PROCESS;
        try {
            log.debug("订阅主题:{}",topicChargingResult);
            mqttClient.subscribe(topicChargingResult);
            log.debug("订阅主题:{}，完成",topicChargingResult);

            log.debug("订阅主题:{}",topicChargingProcess);
            mqttClient.subscribe(topicChargingProcess);
            log.debug("订阅主题:{}，完成",topicChargingProcess);
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void connectionLost(Throwable cause) {
        log.debug("连接丢失，原因:{}",cause);
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        log.debug("收到消息，主题:{},消息:{}",topic,message);
        if (MqttConstants.TOPIC_CHARGING_RESULT.equals(topic)){
            //处理开始充电结果的方法
            handleChargingResult(topic, message);
        } else if (MqttConstants.TOPIC_CHARGING_PROCESS.equals(topic)) {
            //处理充电过程的方法
            handleChargingProcess(topic,message);

        }

    }

    /**
     * 处理订单服务接收到设备发送的充电进程信息的方法
     * @param topic 主题名称
     * @param message  设备发送的消息，是JSON，需要转换为对象
     */
    private void handleChargingProcess(String topic,MqttMessage message){
        ChargingProcessDto chargingProcessDto = null;
        try {
            chargingProcessDto = JsonUtils.toObject(message.toString(),ChargingProcessDto.class);
        }
        catch (Exception e){
            log.error("设备发送的消息无法转换为java对象，topic:{},message:{}", topic, message);
        }
        log.debug("设备发送的消息转换为java对象，{}",chargingProcessDto);
        if (chargingProcessDto != null){
            ChargingProcessVO chargingProcessVO = getCost(chargingProcessDto);
            log.debug("根据设备发送的消息计算出费用，{},并保存到ES",chargingProcessVO);
            saveChargingProcess(chargingProcessDto,chargingProcessVO);
            //向用户同步信息
            sendChargingProcess2User(chargingProcessVO);
        }
    }

    private void sendChargingProcess2User(ChargingProcessVO chargingProcessVO){
        String json = JsonUtils.toJson(chargingProcessVO);
        log.debug("准备向用户发送数据，用户id为:{},数据为:{}",chargingProcessVO.getUserId(),json);
        mqttContext.getWebSocketServer().sendMessage(chargingProcessVO.getUserId(),json);
    }

    private void saveChargingProcess(ChargingProcessDto chargingProcessDto,ChargingProcessVO chargingProcessVO){
        ChargingProcessPO chargingProcessPO = new ChargingProcessPO();
        BeanUtils.copyProperties(chargingProcessDto,chargingProcessPO);
        BeanUtils.copyProperties(chargingProcessVO,chargingProcessPO);
        chargingProcessPO.setId(System.currentTimeMillis());
        log.debug("保存数据到ES数据库，数据为:{}",chargingProcessPO);
        mqttContext.getChargingProcessESRepository().save(chargingProcessPO);
    }
    private ChargingProcessVO getCost(ChargingProcessDto chargingProcessDto) {
        ChargingProcessParam chargingProcessParam = new ChargingProcessParam();
        BeanUtils.copyProperties(chargingProcessDto,chargingProcessParam);
        log.debug("准备调用计价服务，参数:{}",chargingProcessParam);
        JsonResult<ChargingProcessVO> chargingProcessVOJsonResult = mqttContext.getCostClient().calculateCost(chargingProcessParam);
        log.debug("调用计价服务，入参:{},结果:{}",chargingProcessParam,chargingProcessVOJsonResult);
        if (chargingProcessVOJsonResult != null) {
            return chargingProcessVOJsonResult.getData();
        }
        return null;
    }

    /**
     * 处理订单服务接收到设备发送的开始充电结果的方法
     * @param topic 主题名称
     * @param message  设备发送的消息，是JSON，需要转换为对象
     */
    private void handleChargingResult(String topic, MqttMessage message) {
        ChargingResultDto chargingResultDto = null;
        try {
            chargingResultDto = JsonUtils.toObject(message.toString(),ChargingResultDto.class);
        }
        catch (Exception e){
            log.error("设备发送的消息无法转换为java对象，topic:{},message:{}", topic, message);
        }
        log.debug("设备发送的消息转换为java对象，{}",chargingResultDto);
        if (chargingResultDto != null){
            String result = chargingResultDto.getResult();
            if (ChargingConstants.CHARGING_RESULT_SUCCESS.equals(result)){
                log.debug("设备开始充电成功！");
                ChargingOrderSuccessPO chargingOrderSuccessPO = new ChargingOrderSuccessPO();
                chargingOrderSuccessPO.setBillId(chargingResultDto.getOrderNo());
                chargingOrderSuccessPO.setGunId(chargingResultDto.getGunId());
                chargingOrderSuccessPO.setBillStatus(OrderStatusConstants.ORDER_STATUS_PROCESS);
                log.debug("向数据库插入成功订单信息，数据:{}",chargingOrderSuccessPO);
                Integer row = mqttContext.getOrderSuccessMapper().insert(chargingOrderSuccessPO);
                log.debug("向数据库插入成功订单信息，数据:{},受影响行数:{}",chargingOrderSuccessPO,row);
            }else {
                log.debug("设备开始充电失败");
                ChargingOrderFailPO chargingOrderFailPO = new ChargingOrderFailPO();
                chargingOrderFailPO.setBillId(chargingResultDto.getOrderNo());
                chargingOrderFailPO.setGunId(chargingResultDto.getGunId());
                chargingOrderFailPO.setFail_desc("设备响应，但无法充电");
                log.debug("向数据库插入失败订单信息，数据:{}",chargingOrderFailPO);
                Integer row = mqttContext.getOrderFailMapper().insert(chargingOrderFailPO);
                log.debug("向数据库插入失败订单信息，数据:{},受影响行数:{}",chargingOrderFailPO,row);
                log.debug("向客户反馈订单创建失败，发送优惠券");
                log.debug("向后台反馈枪故障，提醒安排人员维修");
                //修改枪状态
                GunStatusUpdateParam gunStatusUpdateParam = new GunStatusUpdateParam();
                gunStatusUpdateParam.setGunId(chargingResultDto.getGunId());
                gunStatusUpdateParam.setStatus(GunStatusConstants.GUN_STATUS_FAIL);
                log.debug("修改枪状态，参数:{}",gunStatusUpdateParam);
                mqttContext.getDeviceClient().updateGunStatus(gunStatusUpdateParam);
            }
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        log.debug("消息发送完成，参数:{}",token);
    }
}
